using AutoMapper;
using StudentManagement.Application.DTOs;
using StudentManagement.Domain.Entities;
using StudentManagement.Domain.Repositories;

namespace StudentManagement.Application.Services;

public class StudentService : IStudentService
{
    private readonly IStudentRepository _studentRepository;
    private readonly IClassRepository _classRepository;
    private readonly IMapper _mapper;

    public StudentService(IStudentRepository studentRepository, IClassRepository classRepository, IMapper mapper)
    {
        _studentRepository = studentRepository;
        _classRepository = classRepository;
        _mapper = mapper;
    }

    public async Task<StudentDTO> GetStudentByIdAsync(int id)
    {
        var student = await _studentRepository.GetByIdAsync(id);
        if (student == null)
        {
            throw new Exception("学生不存在");
        }

        var studentDTO = _mapper.Map<StudentDTO>(student);
        var classInfo = await _classRepository.GetByIdAsync(student.ClassId);
        if (classInfo != null)
        {
            studentDTO.ClassName = classInfo.ClassName;
        }

        return studentDTO;
    }

    public async Task<StudentDTO> GetStudentByStudentIdAsync(string studentId)
    {
        var student = await _studentRepository.GetStudentByStudentIdAsync(studentId);
        if (student == null)
        {
            throw new Exception("学生不存在");
        }

        var studentDTO = _mapper.Map<StudentDTO>(student);
        var classInfo = await _classRepository.GetByIdAsync(student.ClassId);
        if (classInfo != null)
        {
            studentDTO.ClassName = classInfo.ClassName;
        }

        return studentDTO;
    }

    public async Task<IEnumerable<StudentDTO>> GetAllStudentsAsync()
    {
        var students = await _studentRepository.GetAllAsync();
        var studentDTOs = _mapper.Map<IEnumerable<StudentDTO>>(students);
        
        // 为每个学生添加班级名称
        foreach (var studentDTO in studentDTOs)
        {
            var classInfo = await _classRepository.GetByIdAsync(studentDTO.ClassId);
            if (classInfo != null)
            {
                studentDTO.ClassName = classInfo.ClassName;
            }
        }

        return studentDTOs;
    }

    public async Task<IEnumerable<StudentDTO>> GetStudentsByClassIdAsync(int classId)
    {
        var students = await _studentRepository.GetStudentsByClassIdAsync(classId);
        var studentDTOs = _mapper.Map<IEnumerable<StudentDTO>>(students);
        
        // 添加班级名称
        var classInfo = await _classRepository.GetByIdAsync(classId);
        if (classInfo != null)
        {
            foreach (var studentDTO in studentDTOs)
            {
                studentDTO.ClassName = classInfo.ClassName;
            }
        }

        return studentDTOs;
    }

    public async Task<IEnumerable<StudentDTO>> SearchStudentsAsync(string keyword)
    {
        var students = await _studentRepository.SearchStudentsAsync(keyword);
        var studentDTOs = _mapper.Map<IEnumerable<StudentDTO>>(students);
        
        // 为每个学生添加班级名称
        foreach (var studentDTO in studentDTOs)
        {
            var classInfo = await _classRepository.GetByIdAsync(studentDTO.ClassId);
            if (classInfo != null)
            {
                studentDTO.ClassName = classInfo.ClassName;
            }
        }

        return studentDTOs;
    }

    public async Task<StudentDTO> CreateStudentAsync(StudentDTO studentDTO)
    {
        // 验证班级是否存在
        if (!await _classRepository.ExistsAsync(studentDTO.ClassId))
        {
            throw new Exception("班级不存在");
        }

        // 验证学号是否已存在
        var existingStudent = await _studentRepository.GetStudentByStudentIdAsync(studentDTO.StudentId);
        if (existingStudent != null)
        {
            throw new Exception("学号已存在");
        }

        var student = _mapper.Map<Student>(studentDTO);
        student.EnrollmentDate = DateTime.Now;
        student.Status = "在读";

        await _studentRepository.AddAsync(student);

        // 更新班级的学生总数
        var classInfo = await _classRepository.GetByIdAsync(student.ClassId);
        if (classInfo != null)
        {
            classInfo.TotalStudents += 1;
            await _classRepository.UpdateAsync(classInfo);
        }

        var createdStudentDTO = _mapper.Map<StudentDTO>(student);
        createdStudentDTO.ClassName = classInfo?.ClassName;

        return createdStudentDTO;
    }

    public async Task<StudentDTO> UpdateStudentAsync(int id, StudentDTO studentDTO)
    {
        var existingStudent = await _studentRepository.GetByIdAsync(id);
        if (existingStudent == null)
        {
            throw new Exception("学生不存在");
        }

        // 验证班级是否存在
        if (!await _classRepository.ExistsAsync(studentDTO.ClassId))
        {
            throw new Exception("班级不存在");
        }

        // 验证学号是否已被其他学生使用
        var studentWithSameId = await _studentRepository.GetStudentByStudentIdAsync(studentDTO.StudentId);
        if (studentWithSameId != null && studentWithSameId.Id != id)
        {
            throw new Exception("学号已被其他学生使用");
        }

        // 如果班级发生变化，更新原班级和新班级的学生总数
        if (existingStudent.ClassId != studentDTO.ClassId)
        {
            // 减少原班级的学生总数
            var oldClass = await _classRepository.GetByIdAsync(existingStudent.ClassId);
            if (oldClass != null)
            {
                oldClass.TotalStudents = Math.Max(0, oldClass.TotalStudents - 1);
                await _classRepository.UpdateAsync(oldClass);
            }

            // 增加新班级的学生总数
            var newClass = await _classRepository.GetByIdAsync(studentDTO.ClassId);
            if (newClass != null)
            {
                newClass.TotalStudents += 1;
                await _classRepository.UpdateAsync(newClass);
            }
        }

        // 更新学生信息
        _mapper.Map(studentDTO, existingStudent);
        await _studentRepository.UpdateAsync(existingStudent);

        var updatedStudentDTO = _mapper.Map<StudentDTO>(existingStudent);
        var classInfo = await _classRepository.GetByIdAsync(existingStudent.ClassId);
        updatedStudentDTO.ClassName = classInfo?.ClassName;

        return updatedStudentDTO;
    }

    public async Task DeleteStudentAsync(int id)
    {
        var student = await _studentRepository.GetByIdAsync(id);
        if (student == null)
        {
            throw new Exception("学生不存在");
        }

        // 更新班级的学生总数
        var classInfo = await _classRepository.GetByIdAsync(student.ClassId);
        if (classInfo != null)
        {
            classInfo.TotalStudents = Math.Max(0, classInfo.TotalStudents - 1);
            await _classRepository.UpdateAsync(classInfo);
        }

        await _studentRepository.DeleteAsync(id);
    }

    public async Task<bool> StudentExistsAsync(int id)
    {
        return await _studentRepository.ExistsAsync(id);
    }

    public async Task<bool> StudentIdExistsAsync(string studentId)
    {
        var student = await _studentRepository.GetStudentByStudentIdAsync(studentId);
        return student != null;
    }
}